本篇是接續一、用skeleton code解釋tensorflow model程式執行方式(tf.keras) ep.1,這第一篇主要要講的是我學到的一個具彈性的程式碼要怎麼寫,才能在要擴充時,少點架構的修改,可以專注於深度學習需要花時間處理的部分:資料、與模型本身。
其中第2段與第3段的內容都在ep.1,還沒看過的可以先去看。
前面第2段我有介紹一下datasets的具體架構,還有他的label的存法不同,但是都是一樣的道理。
常見的label像是,segmentation任務,會直接用影像的全部pixel去做標記,所以這類的label基本上就會直接是2d影像,像brats的資料也是類似情況,只不過他是3d影像;
那classification的任務最直觀的作法,是用資料夾去命名,同名的資料夾內就放同一個種類的object,當然應該也會有用影像名稱直接命名的,不過這個如果是手動搜集,除非寫程式改檔名,否則一個一個改的效率太低。
類似detection的任務,通常會給bounding box,需要取得的是bounding box的「左上角與右下角的座標」,或是「左上角的座標與bbox長還有bbox寬」。那這類資料的label通常會用json檔去保存,所以在解析這類dataset時,就需要去了解他的json檔裡,把task需要的資訊給拿出來,其他沒用的就忽略掉。
那第3段的部分,是大概統整了深度學習的應用,它完整要做的事會有哪些步驟,我之前在練習時以為做完Step1, 7, 11就可以了,可是做完其實很空虛,因為什麼東西都沒有留下。
後來加進Step8, 10感覺好像有點東西了,但是每次調參數都很像是在擲筊在賭博,最初試著訓練幾個模型後發現糟了,完全忘記之前的模型,是用什麼參數訓練的。主要的原因是同時會有很多東西在改動,不只是參數,有時候程式跑一跑就會有bug,或是要加入新的程式進去,在這樣子的情況下,要怎麼比較模型之間的差異?
之後有時間我會考慮把它做成流程圖,不過那是之後的事情了。
文章分段:
前面大概回憶過ep.1講的2、3段,ep.2就接著從第4段開始吧!
真的在建立與訓練模型時,要撰寫的程式有幾個功能要做到:
要把以上功能納進組織良好的程式裡,取決於工程師的經驗與習慣。越是有經驗的工程師,往後架構的改動次數亦會減少,不過沒經驗也不要擔心,一切從模仿開始,仿著仿著就會有經驗開始累積了。
下面我仿造之前實習的地方,還有tensorflow的deeplab的程式架構,是我覺得整理起來比較容易的架構。
目前,我的作法是這樣的,如果出現兩種情況,我就會把project獨立出來。
第一種情況是使用的深度學習平台/框架不同,顯而易見的原因,就是因為程式架構與寫法太不同了,有時候甚至連使用的語言也不同;另外,雖然pytorch跟tensorflow都是用python撰寫,但程式的呼叫上就有極大的不同;再舉一個例子,甚至是tensorflow本身,除了有scratch的寫法,還有調用tf.estimator跟tf.keras的不同。
為了不讓一個月後的自己爆炸,出現這種情況無論如何一定得分開。
第二種情況是task不同,我會將project獨立出來,也就是說,如果都是在做相同的segmentation task,不論是找車子,還是找腦瘤或是找各種物件,我都會放在同一個project裡面。原因有幾個:通常相同task的模型可以互通有無、tfrecord的格式類似、資料前處理的方法類似、用來評分的metric亦可以通共有無,基於以上幾個原因,我認為同task就併在同個project,然後task不同的話就分開。
在接續講下去之前,先說明一下,因為接下來的部分,會涉及到寫程式的部分,也就會開始有特定的程式語言出現。我目前主要用的是tensorflow框架,也是我這次的主題,所以接下來的虛擬碼與程式撰寫,都會圍繞著tensorflow及python展開。至於其他框架的部分...就以後再說。
.
└── projects
├──project1
| ├── core/
| ├── datasets/
| ├── logs/
| ├── models/
| ├── evaluate.py
| ├── predict.py
| ├── README.md
| └── train.py
├── project2
| └── ...
├── .gitignore
├── CHANGELOG.md
└── README.md
那每個project內部都會有四個資料夾core/
、datasets/
、logs/
、models/
,還有三個主要程式,train
、predict
、evaluate
,接下來我會依序講解每個的用途是什麼。
core/
.
└── core/
├── unet.py
├── backbone/
└── ...
在deeplab中,core/
資料夾是用來放:自己製作的layer
,還有backbone(feature extractor)
的地方,能呼叫到完整的模型架構,是寫在上層的model.py
裡。
題外話,先撇開架構不提,前段提到的backbone也是深度學習領域中需要了解的概念。我第一次接觸到這個名詞是在論文裡,上下翻完論文以及去找過網路上關於backbone的解釋後,對於如何實際應用還是一知半解。而我真正理解它,是在讀完實習待的地方用的模型才有了具體的概念。我之後的文章會再帶到這個部分,有興趣的可以再來看。
而我這裡沒有model.py
,我是直接將模型與backbone都統一放在core/
,這邊要誠實說的是,我目前使用的backbone都還是安裝來的程式,還沒有成功的把別人分享的程式抽取出要的部分放入,還是有bug無法解決。
這裏想推薦正在使用keras API進行segmentation task的人一個github:qubvel的segmentation_models,裡面有寫得超棒的架構,想要自己寫一個靈活的keras模型的人可以拿來參考。
datasets/
datasets
這個資料夾的結構蠻龐大的,主要原因是因為每個dataset的儲存方式都不太一樣,尤其是公開資料集,每個都會有自己的規則。
那這個部分要做的功能就是,將各個dataset,透過tf.data API,轉成統一的儲存結構,一旦把資料的儲存結構統一,就可以用相同的程式架構將資料轉換成tensor,進行前處理或是進入模型之中。
先給你們看完整的資料夾架構。
.
└── datasets
├── DATASET_NAME
| ├── annotations/
| | ├── ***_seg.nii.gz or
| | ├── ***.png or
| | ├── ***.json
| | └── ...
| ├── data/
| | ├──pred/
| | ├──train/
| | └──val/
| └── tfrecords
| ├──DATASET_NAME_pred.tfrecord
| ├──DATASET_NAME_train.tfrecord
| └──DATASET_NAME_val.tfrecord
|
├── build_DATASET_NAME_to_tfrecord.py
├── build_data.py
├── data_generater.py
├── preprocesses.py
├── tfrecord2image_DATASET_NAME_format.py
└── ...
首先想說明下面程式的部分,build_DATASET_NAME_to_tfrecord.py
就是根據不同dataset去處理,可以先看deeplab/datasets略窺一二,它本身有提供ade20k、cityscapes、voc2012三個dataset的處理方式。基本功能是將raw data轉成tfrecord。
build_data.py
算是是決定tfrecord架構的地方,像deeplab的build_data.py136行的地方就是他訂定的基本segmentation需要用到的資料。
data_generater.py
是處理tfrecord轉成模型可用的data的程式,我的寫法就不是參考deeplab的寫法了,之後會再解釋。
preprocesses.py
就是集結了所有可以通用的前處理的地方,這個部分也留待之後闡述。
tfrecord2image_DATASET_NAME_format.py
:這個程式是在將tfrecord裡面的東西,轉回來視覺化地呈現,基本也算是build_to_tfreocrd
的測試程式碼,一樣之後細談。
最後是我略過的dataset本身的部分,我上面列出的部分是一種存放方式的舉例,大部分情況,由於dataset的所佔的容量很大,它通常會被另外放在別的硬碟提供取用,而內層的tfrecords/
就是存放build好的tfrecord。
天阿,時間差不多了,今天也花了大概3個小時的時間,才把第4段講到一個小段落而已,我知道我還有2個資料夾和3個主要程式沒有解釋,但其實他們的架構也比較簡單,所以我決定把他們和實際的程式碼留到明天再繼續講。
一樣,感謝你的觀看,請不要吝嗇留下你的建言,讓還在學習的我能夠多開開眼界。
或是有什麼部分是你想要知道的更多的或是我沒有講清楚的部分,可以留言讓我知道,我會再把他們穿插進我的文章裡,再次謝謝你的觀看。